<?php
namespace Plu\Library\Models\Tga\Live;

use Phalcon\Mvc\Model,
    Phalcon\Db\Column,
    Phalcon\Mvc\Model\Resultset\Simple as Resultset,
    Plu\Library\Models\Platform\Tag\TagMap as TagMapModel;

class Rooms extends Model {
    public $id;//int(10)

    public $name;//varchar(255)

    public $domain;//varchar(64)

    public $uid;

    public $avatar;//varchar(255)

    public $grade;

    public $status;

    public $broadcast_begin;

    public $broadcast_duration;

    public $views;

    public $admire;

    public $videos;

    public $_type;

    public $_subtype;

    public $preview;

    public $preview2;

    public $gameid;

    public $gametag;

    public $gamename;

    public $skin;

    public $flowers;

    public $followers;

    public $glamours;

    public $tag;

    public $verification;

    public $totaldays;

    public $totallivelength;

    public $weight;

    public $stick;

    public $belle;

    public $auth;

    public $ugc;

    public $is_broadcast;

    /**
     * 房间加密
     */
    public $lockable;

    /**
     * 房间收费
     */
    public $fee;

    /**
     * 直播流来源
     */
    public $live_source;

    /**
     * 流类型
     */
    public $stream_types;

    //地理信息
    public $longitude;

    public $latitude;

    public $address; 

    public $vid;

    public $lastupdate;

    ///{{{
    // 内部使用属性
    protected $attr_exroomTags = array();

    protected $attr_roomTags = array();

    protected $attr_where = array();

    protected $attr_bind  = array();

    protected $attr_bindTypes = array();

    protected $attr_roomIds = array();
    ///}}}

    /**
     * 过滤美女类型直播
     */
    const FILTER_STREAM_BELLE             = 0x01;
    /**
     * 过滤kespa的直播
     */
    const FILTER_STREAM_KESPA             = 0x02;
    /**
     * 只获取有腾讯vid的直播,已经废弃，可以通过stream_type来判断
     */
    const FILTER_STREAM_VID               = 0x04;
    /**
     * 只获取美女类型的直播
     */
    const FILTER_STREAM_GET_BELLE         = 0x08;
    /**
     * 只获取kespa的直播
     */
    const FILTER_STREAM_GET_KESPA         = 0x10;
    /**
     * 只获取 龙珠娱乐 直播
     */
    const FILTER_STREAM_GET_Entertainment = 0x20;
    /**
     * 过滤 龙珠娱乐 直播
     */
    const FILTER_STREAM_Entertainment     = 0x40;

    /**
     * 只获取音乐项目
     */
    const FILTER_STREAM_GET_MUSIC         = 0x80;

    /**
     * 过滤音乐项目
     */
    const FILTER_STREAM_MUSIC             = 0x100;

    /**
     * 只获取方言
     */
    const FILTER_STREAM_GET_DIALECT       = 0x200;

    /**
     * 过滤方言主播
     */
    const FILTER_STREAM_DIALECT           = 0x400;

    /**
     * 只获取龙珠男
     */
    const FILTER_STREAM_GET_MAN           = 0x800;

    /**
     * 只获取异域美女
     */
    const FILTER_STREAM_GET_FBELLE        = 0x1000;

    /**
     * 只获取APP随拍
     */
    const FILTER_USTREAM_GET_APP          = 0x2000;


    /**
     * 过滤APP随拍
     */
    const FILTER_USTREAM_APP              = 0x4000;

    /**
     * 主播推流工具
     */
    const FILTER_USTREAM_GET_HD           = 0x8000;

    /**
     * 过滤主播推流工具
     */

    const FILTER_USTREAM_HD               = 0x10000;

    /**
     * OBS推流工具
     */
    const FILTER_USTREAM_GET_OBS          = 0x20000;

    /**
     * 过滤obs
     */
    const FILTER_USTREAM_OBS              = 0x40000;

    /**
     * 安卓推流工具
     */
    const FILTER_USTREAM_GET_ANDROIDTOOOLS          = 0x80000;

    /**
     * plu桌面
     */
    const FILTER_USTREAM_GET_PLUPC        = 0x100000;

    const STREAM_SORT_KEYS = array(
        'top', 
        'followers', 
        'views',
        'newest',
        'newbie',
        'hotrecommend',
        'officalcert',
        'weight',
        'rvs',
        'customize' //根据roomids进行排序
    );

    const STREAM_TYPES = array(
        'Tga'      => 1,  //随心播
        'QqPush'   => 2,  //qqpush(qq,obs)
        'QqStream' => 3,  //Stream之外腾讯外站直播
        'Twitch'   => 4,  //twitch
        'V17173'   => 5,  //17173
        'Qtlive'   => 6,  //qt
        'Sina'     => 7,  //sina
        'FengYun'  => 8,  //风云
        'WS'       => 9,  //网宿
        'Qiniu'    => 10, //App全民直播之七牛
        'Ksyun'    => 11, //App全民直播之金山云
        'Qclound'  => 12, //App直播之腾讯云
    );

    const LIVE_SOURCE = array(
        'HDBroadcast'   => 0x01,  //高清直播工具App
        'SnapshotApp'   => 0x02,  //龙珠直播App随拍模块
        'SnapshotObs'   => 0x04,  //OBS推随拍
        'Obs'           => 0x08,  //OBS
        'PluApp'        => 0x10, //PLU桌面客户端
        'AndroidTools'  => 0x80, //测试128的源
    );


    const CACHE_TIME = 60;

    /**
     * 取交集数据
     */
    const query_rooms_match_tag_intersect = "SELECT tgarooms.*
        FROM tgarooms
        LEFT JOIN TagMap AS tm ON (tgarooms.id = tm.ItemId)
        WHERE %s
        GROUP BY tgarooms.id HAVING COUNT(1) %s %d
        ORDER BY %s
        LIMIT %d, %d";

    const query_count_match_tag_intersect = "SELECT COUNT(1) as sumatory FROM (
        SELECT 1 FROM tgarooms
        LEFT JOIN TagMap AS tm ON (tgarooms.id = tm.ItemId)
        WHERE %s
        GROUP BY tgarooms.id HAVING COUNT(1) %s %d) AS T";

    const query_count_match_tag_minus = "SELECT COUNT(1) as sumatory FROM tgarooms
        WHERE %s AND EXISTS        
        (
            SELECT * FROM TagMap as tm WHERE %s %s not EXISTS (SELECT * from TagMap where ItemType = 3 AND %s AND ItemId = tm.ItemId) AND tgarooms.id = tm.ItemId
        )";

    const query_rooms_match_tag_minus = "SELECT tgarooms.* FROM tgarooms
        WHERE %s AND EXISTS        
        (
            SELECT * FROM TagMap as tm WHERE ItemType = 3 AND %s %s not EXISTS (SELECT * from TagMap where ItemType = 3 AND %s AND ItemId = tm.ItemId) AND tgarooms.id = tm.ItemId
        )
        ORDER BY %s
        LIMIT %d, %d";


    public function getSource() {
        return "tgarooms";
    }

    public function initialize() {
        $this->setReadConnectionService('db.longzhulivereadonly.slave');
        $this->setWriteConnectionService('db.longzhulive');
    }

    //always validate 
    public function validation() {
        return true;
    }

    public function setBroadcastStatus($isBroadcast = 'online') {
        switch ($isBroadcast) {
            case 'all':
                break;
            case 'online':
                $this->attr_where[] = ' is_broadcast = 1 ';//强制直播状态
                break;
            case 'offline':
                $this->attr_where[] = ' is_broadcast = 0';
                break;
        }

        return $this;
    }

    public function setLockableStatus($isLocked = 'all') {
        switch($isLocked) {
            //取所有
            case "all" :
                //默认取所有的
                break;
            //只取加密的
            case "lock" :
                $this->attr_where[] = ' lockable = 1 ';  
                break;
            //只取不加密的
            case "unlock" :
                $this->attr_where[] = ' lockable = 0 '; 
                break;
        }

        return $this;
    }

    public function setFeeStatus($isFee = 'all') {
        switch($isFee) {
            //取所有
            case "all" :
                //默认取所有的
                break;
            //只取收费的
            case "fee" :
                $this->attr_where[] = ' fee > 0 ';
                break;
            //只取免费的
            case "unfee":
                $this->attr_where[] = ' fee = 0 ';
                break;
        }
        
        return $this;
    }

    public function setRectangleCover($isRectangle = false) {
        if($isRectangle) {
            $this->attr_where[] = 'previw LIKE "http://img2%"';
        }
        return $this;
    }

    public function setSquareCover($isSquare = false) {
        if($isSquare) {
            $this->attr_where[] = 'preview2 LIKE "http://img2%"';
        }
        return $this;
    }

    public function setGames($games) {
        //force convert int
        $games = array_map(intval, $games);
        $this->attr_where[] = sprintf(" gameid in (%s) ", join(",", $games));

        return $this;
    }

    public function setExgames($exgames) {
        $exgames = array_map(intval, $exgames);

        $this->attr_where[] = sprintf(" gameid not in (%s) ", join(",", $exgames));

        return $this;
    }

    public function setRoomIds($roomIds) {
        $roomIds = array_map(intval, $roomIds);

        $this->attr_roomIds = $roomIds;

        $this->attr_where[] = sprintf(" tgarooms.id in (%s) ", join(",", $roomIds));

        return $this;
    }

    public function setExroomIds($exroomIds) {
        $exroomIds = array_map(intval, $exroomIds);

        $this->attr_where[] = sprintf(" tgarooms.id not in (%s) ", join(",", $exroomIds));

        return $this;
    }

    public function setFilter($filter) {
        if ($filter <= 0) {
            return $this;
        }

        /**
         * 修正这里过滤一些数据 需要使用tag
         */
        if (($filter & self::FILTER_STREAM_BELLE) == self::FILTER_STREAM_BELLE) {
            $this->attr_exroomTags = ['美女星主播'];
        }

        if (($filter & self::FILTER_STREAM_KESPA) == self::FILTER_STREAM_KESPA) {
            $this->attr_where[] = " _type != 5 ";
        }

        if (($filter & self::FILTER_STREAM_GET_BELLE) == self::FILTER_STREAM_GET_BELLE) {
            $this->attr_roomTags = ['美女星主播'];
        }
        if (($filter & self::FILTER_STREAM_GET_KESPA) == self::FILTER_STREAM_GET_KESPA) {
            $this->attr_where[] = " _type = 5 ";
        }
        if (($filter & self::FILTER_STREAM_GET_Entertainment) == self::FILTER_STREAM_GET_Entertainment) {
            $this->attr_roomTags = ['龙珠娱乐'];
        }
        if (($filter & self::FILTER_STREAM_Entertainment) == self::FILTER_STREAM_Entertainment) {
            $this->attr_exroomTags = ['龙珠娱乐'];
        }

        if (($filter & self::FILTER_STREAM_GET_MUSIC) == self::FILTER_STREAM_GET_MUSIC) {
            $this->attr_roomTags = ['龙珠音乐'];
        }
        if (($filter & self::FILTER_STREAM_MUSIC) == self::FILTER_STREAM_MUSIC) {
            $this->attr_exroomTags = ['龙珠音乐'];
        }

        if (($filter & self::FILTER_STREAM_GET_DIALECT) == self::FILTER_STREAM_GET_DIALECT) {
            $this->attr_roomTags = ['乡音主播'];
        }
        if (($filter & self::FILTER_STREAM_DIALECT) == self::FILTER_STREAM_DIALECT) {
            $this->attr_exroomTags = ['乡音主播'];
        }

        if (($filter & self::FILTER_STREAM_GET_MAN) == self::FILTER_STREAM_GET_MAN) {
            $this->attr_roomTags = ['龙珠男神'];
        }

        if (($filter & self::FILTER_STREAM_GET_FBELLE) == self::FILTER_STREAM_GET_FBELLE) {
            $this->attr_roomTags = ['异域美女'];
        }

        //需要显示指定随拍的内容
        $liveSource = 0;
        if (($filter & self::FILTER_USTREAM_GET_HD) == self::FILTER_USTREAM_GET_HD) {
            $liveSource |= self::LIVE_SOURCE['HDBroadcast'];
        }
        if (($filter & self::FILTER_USTREAM_GET_APP) == self::FILTER_USTREAM_GET_APP) {
            $liveSource |= self::LIVE_SOURCE['SnapshotApp'];
        }
        if (($filter & self::FILTER_USTREAM_GET_OBS) == self::FILTER_USTREAM_GET_OBS) {
            $liveSource |= self::LIVE_SOURCE['SnapshotObs'];
        }
        //增加128的live_source
        if (($filter & self::FILTER_USTREAM_GET_ANDROIDTOOOLS) == self::FILTER_USTREAM_GET_ANDROIDTOOOLS) {
            $liveSource |= self::LIVE_SOURCE['AndroidTools'];
        }

        if (($filter & self::FILTER_USTREAM_GET_PLUPC) == self::FILTER_USTREAM_GET_PLUPC) {
            $liveSource |= self::LIVE_SOURCE['PluApp'];
        }

        if ($liveSource > 0) {
            $this->attr_where[] = sprintf(' live_source & %1$d > 0', $liveSource);
        }


        //过滤指定的直播源
        $liveSource = 0;
        if (($filter & self::FILTER_USTREAM_HD) == self::FILTER_USTREAM_HD) {
            $liveSource |= self::LIVE_SOURCE['HDBroadcast'];
        }
        if (($filter & self::FILTER_USTREAM_APP) == self::FILTER_USTREAM_APP) {
            $liveSource |= self::LIVE_SOURCE['SnapshotApp'];
        }
        if (($filter & self::FILTER_USTREAM_OBS) == self::FILTER_USTREAM_OBS) {
            $liveSource |= self::LIVE_SOURCE['SnapshotObs'];
        }

        if ($liveSource > 0) {
            $this->attr_where[] = sprintf(' live_source & %1$d = 0', $liveSource);
        }
        
        return $this;
    }

    public function setParams($params) {
        if (empty($params)) {
            return $this;
        }

        if (is_array($params)) {
            $this->attr_where[] = join(' AND ', $params);
        } elseif (is_string($params)) {
            $this->attr_where[] = $params;
        }

        return $this;
    }

    public function reset() {
        $this->attr_where      = [];
        $this->attr_bind       = array();
        $this->attr_bindTypes  = array();
        $this->attr_roomTags   = array();
        $this->attr_exroomTags = array();
        $this->attr_roomIds    = array();

        return $this;
    }

    /**
     * 获取所有明星数据
     *
     * @param $start_index 
     * @param $max_results
     * @param $sortby  排序方式 top 和 newest, kespa
     * @param $games   查询指定的游戏
     * @param $exgames 排除指定的游戏
     * @param $channels 查询指定的房间
     * @param $excludes 排除指定的房间
     * @param $isdomain default true  传入的channels或者excludes是否是domain，false为roomids
     * @param $is_broadcast default true 默认只搜索在线房间
     * @param $filter 过滤数据 1 美女 2 kespa 4 只含有vid的直播
     * @param $strict 严格匹配模式，AND 
     */
    public function getRooms($start_index, $max_results, $sortby = 'top', $games = array(), $exgames = array(), $roomIds = array(), $exroomIds = array(), $roomTags = array(), $exroomTags = array(), $is_broadcast = true, $setRectangle = false, $setSquare = false, $isLocked = 'all', $isFee = 'all', $filter = 0, $params = array(), $strict = false) {
        $this->reset();

        $this->setBroadcastStatus($is_broadcast);

        $this->setLockableStatus($isLocked);
        $this->setFeeStatus($isFee);

        if (!empty($games)) {
            $this->setGames($games);
        }

        if (!empty($exgames)) {
            $this->setExgames($exgames);
        }

        if (!empty($roomIds)) {
            $this->setRoomIds($roomIds);
        }

        if (!empty($exroomIds)) {
            $this->setExroomIds($exroomIds);
        }

        $filter = intval($filter);
        if ($filter > 0) {
            $this->setFilter($filter);
        }

        if($setRectangle) {
            $this->setRectangleCover($setRectangleCover);
        }

        if($setSquare) {
            $this->setSquareCover($setSquareCover);
        }

        return $this->getStreams($start_index, $max_results, $sortby, $roomTags, $exroomTags, $strict);
    }

    public function getStreams($start_index, $max_results, $sortby, $roomTags = array(), $exroomTags = array(), $strict = false) {
        $sort = "";

        //热门推荐处理
        switch ($sortby) {
            case 'newbie':
                $this->attr_where[] = " ugc = 1 ";
                $sort = "views DESC";
                break;
            case 'hotrecommend': //热推
                $this->attr_where[] = " ugc in (3, 4) ";
                $sort = "views DESC";
            case "officalcert": //官方认证 不含ugc数据
                $this->attr_where[] = " ugc in (2, 3, 4) ";
                $sort = "stick DESC, views DESC";
                break;
            case 'newest':
                $sort = "broadcast_begin DESC";
                break;
            case 'views':
                $sort = "views DESC";
                break;
            case 'followers':
                $sort = 'followers DESC';
                break;
            case 'weight':
                $sort = 'weight DESC';//根据权重分数排序
                break;
            case 'rvs':
                $sort = 'rvs DESC';
                break;
            case 'customize':  //根据传入的roomId 进行排序
                //TODO: 性能需要优化
                if (!empty($this->attr_roomIds)) {
                    $fields = join(",", $this->attr_roomIds);
                    $sort = " find_in_set(id, '$fields')";
                    break;
                }
            default: //老版本, 默认为top
                $sort = "stick DESC, views DESC";
                break;
        }

        $roomTags = array_merge($this->attr_roomTags, $roomTags);
        $exroomTags = array_merge($this->attr_exroomTags, $exroomTags);

        if (empty($roomTags) && empty($exroomTags)) {
            $where = join(" AND ", $this->attr_where);

            //clean tgarooms
            $where = str_replace('tgarooms.', '', $where);

            $params = array(
                $where,
                "bind"      => $this->attr_bind,
                "bindTypes" => $this->attr_bindTypes
            );

            $totalCount = self::count($params);

            $params['offset'] = $start_index;
            $params['limit'] = $max_results;
            $params['order'] = $sort;

            $items = self::find($params);
        } else {
            $connection = $this->getReadConnection();

            //生成where语句
            //TODO  在字符串下 or/and 比 in/not in要快
            if (!empty($roomTags)) {
                $roomTags = array_values(array_unique($roomTags));

                $roomTagsSql = array();
                $len = count($roomTags);

                for ($c = 0; $c < $len; $c++) {
                    $p = "trt{$c}";
                    $roomTagsSql[] = " TagName = :{$p}: ";
                    $this->attr_bind[$p] = $roomTags[$c];
                    $this->attr_bindTypes[$p] = Column::BIND_PARAM_STR;
                }
            }

            if (!empty($exroomTags)) {
                $exroomTags = array_values(array_unique($exroomTags));

                $exroomTagsSql = array();
                $len = count($exroomTags);

                for ($c = 0; $c < $len; $c++) {
                    $p = "tnrt{$c}";
                    $exroomTagsSql[] = " TagName = :{$p}: ";
                    $this->attr_bind[$p] = $exroomTags[$c];
                    $this->attr_bindTypes[$p] = Column::BIND_PARAM_STR;
                }
            }

            if (!empty($exroomTagsSql)) {
                //使用差集
                if (!empty($roomTagsSql)) {
                    $roomTagsSql = '(' . join( ' OR ', $roomTagsSql) . ')';
                }

                $exroomTagsSql = '(' . join( ' OR ', $exroomTagsSql) . ')';

                $where = join(" AND ", $this->attr_where);

                //取出数量
                $phql = sprintf(self::query_count_match_tag_minus, $where, !empty($roomTagsSql) ? $roomTagsSql : '', !empty($roomTagsSql) ? 'AND' : '', $exroomTagsSql);

                $c = $connection->convertBoundParams($phql, $this->attr_bind);
                $phql = $c['sql'];
                $_bind = $c['params'];

                $items = new Resultset(null, $this, $this->getReadConnection()->query($phql, $_bind));
                $totalCount = $items->toArray()[0]['sumatory'];

                //获得结果集
                $phql = sprintf(self::query_rooms_match_tag_minus, $where, !empty($roomTagsSql) ? $roomTagsSql : '', !empty($roomTagsSql) ? 'AND' : '', $exroomTagsSql, $sort, $start_index, $max_results);
                $c = $connection->convertBoundParams($phql, $this->attr_bind);
                $phql = $c['sql'];
                $_bind = $c['params'];
                $items = new Resultset(null, $this, $this->getReadConnection()->query($phql, $_bind));
            } elseif (!empty($roomTagsSql)) {
                //使用交集
                $this->attr_where[] = '(' . join( ' OR ', $roomTagsSql) . ')';
                $count = count($roomTags);

                //强制使用ItemType = 3
                $this->attr_where[] = sprintf("ItemType = %d", TagMapModel::ITEM_TYPES['ROOM']);

                $where = join(" AND ", $this->attr_where);
                //总数据
                $phql = sprintf(self::query_count_match_tag_intersect, $where, $strict ? '=' : '>', $strict ? $count : 0);


                $c = $connection->convertBoundParams($phql, $this->attr_bind);
                $phql = $c['sql'];
                $_bind = $c['params'];
                $_bindTypes = array_values($this->attr_bindTypes);
                $items = new Resultset(null, $this, $this->getReadConnection()->query($phql, $_bind, $_bindTypes));

                $totalCount = $items->toArray()[0]['sumatory'];


                $phql = sprintf(self::query_rooms_match_tag_intersect, $where, $strict ? '=' : '>', $strict ? $count : 0, $sort, $start_index, $max_results);
                $c = $connection->convertBoundParams($phql, $this->attr_bind);
                $phql = $c['sql'];
                $_bind = $c['params'];
                $items = new Resultset(null, $this, $this->getReadConnection()->query($phql, $_bind, $_bindTypes));
            }
        }

        if (empty($totalCount)) {
            $totalCount = 0;
        }

        if (count($items)) {
            $items = $items->toArray();
        } else {
            $items = [];
        }


        $stars = array($totalCount, $items);

        return $stars;
    }
}
